package com.utilities.IO.fileWriters;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Set;

import com.utilities.IO.FileUtilities;
import com.utilities.dataStructures.Range;
import com.utilities.fastaUtilities.MummerUtilities;
import com.utilities.fastaUtilities.OtherUtilities;
import com.utilities.parsers.ContigsStatsGenerator;


public class PrepareSNPTable {
	private String allDiffsFile_7328 = null;
	private String headers_7328 = null;
	private String allDiffsFile_gamma22 = null;
	private String headers_gamma22 = null;
	private String allDiffsFile_gamma52 = null;
	private String headers_gamma52 = null;
	private String allDiffsFile_gamma70 = null;
	private String headers_gamma70 = null;
	private String headers = null;
	private String gbkFile = null;
	private String contigs_7328 = null;
	private String contigs_gamma22 = null;
	private String contigs_gamma52 = null;
	private String contigs_gamma70 = null;
	private String withGenes = null;
	private String tilingFile = null;
	private String snps = null;
	private ArrayList<Range> finalRanges = null;
	private int seqLength = 4639675;
	
	public static void main(String[] args) throws Exception
	{
		String[] strs = new String[2];
		strs[0] = "Reference" ; strs[1] = "Accno";
		
		args = new String[18];
		args[0] = "C:/Users/bansalp/Desktop/data/toSend/7328/454AllDiffs.txt";
		args[1] = "C:/Users/bansalp/Desktop/data/toSend/7328/headers.txt";
		args[2] = "C:/Users/bansalp/Desktop/data/toSend/gamma22/454AllDiffs.txt";
		args[3] = "C:/Users/bansalp/Desktop/data/toSend/gamma22/headers.txt";
		args[4] = "C:/Users/bansalp/Desktop/data/toSend/gamma52/454AllDiffs.txt";
		args[5] = "C:/Users/bansalp/Desktop/data/toSend/gamma52/headers.txt";
		args[6] = "C:/Users/bansalp/Desktop/data/toSend/gamma70/454AllDiffs.txt";
		args[7] = "C:/Users/bansalp/Desktop/data/toSend/gamma70/headers.txt";
		args[8] = "C:/Users/bansalp/Desktop/headers6.txt";
		args[9] = "C:/Users/bansalp/Desktop/data/gbkFile.gbk";
		args[10] = "C:/Users/bansalp/Desktop/data/toSend/7328/454AllContigs.fna";
		args[11] = "C:/Users/bansalp/Desktop/data/toSend/gamma22/454AllContigs.fna";
		args[12] = "C:/Users/bansalp/Desktop/data/toSend/gamma52/454AllContigs.fna";
		args[13] = "C:/Users/bansalp/Desktop/data/toSend/gamma70/454AllContigs.fna";
		args[14] = "C:/Users/bansalp/Desktop/allNew2.txt";
		args[15] = "C:/Users/bansalp/Desktop/genes.txt";
		args[16] = "C:/Users/bansalp/Desktop/data/snps.txt";
		args[17] = "C:/Users/bansalp/Desktop/data/tiling.txt";
	}
	
	public void run() throws Exception
	{
		String[] strs = new String[2];
		strs[0] = "Reference" ; strs[1] = "Accno";
		ArrayList<Range> diffs_7328 = fetchDifferences(strs, allDiffsFile_7328);
		Collections.sort(diffs_7328,new RangeComparator());
		
		ArrayList<Range> diffs_gamma22 = fetchDifferences(strs,allDiffsFile_gamma22);
		Collections.sort(diffs_gamma22,new RangeComparator());
		
		
		ArrayList<Range> diffs_gamma52 = fetchDifferences(strs,allDiffsFile_gamma52);
		Collections.sort(diffs_gamma52,new RangeComparator());
		
		
		ArrayList<Range> diffs_gamma70 = fetchDifferences(strs,allDiffsFile_gamma70);
		Collections.sort(diffs_gamma70,new RangeComparator());
		
		ArrayList<String> snps = FileUtilities.readListFromFile(this.snps);
		ArrayList<Range> snpRangs_singleEnds  = new ArrayList<Range>();
		
		for (String str : snps)
		{
			int i = Integer.parseInt(str.split("\t")[0]);
			Range r = new Range(i, i, str);
			snpRangs_singleEnds.add(r);
		}
		ArrayList<Range> gaps_singleEnds = MummerUtilities.getGaps(tilingFile);
		
		ContigsStatsGenerator generator = ContigsStatsGenerator.getInstance().setInputScaffoldFile
		(contigs_7328).setSeqReadLength(seqLength).setConsiderGaps(true);
		if (!generator.generateStats()) return ;
		ArrayList<Range> gaps_7328 = generator.getEachGapInfo();
		
		generator = ContigsStatsGenerator.getInstance().setInputScaffoldFile
		(contigs_gamma22).setSeqReadLength(seqLength).setConsiderGaps(true);
		if (!generator.generateStats()) return ;
		ArrayList<Range> gaps_gamma22 = generator.getEachGapInfo();
		
		generator = ContigsStatsGenerator.getInstance().setInputScaffoldFile
		(contigs_gamma52).setSeqReadLength(seqLength).setConsiderGaps(true);
		if (!generator.generateStats()) return ;
		ArrayList<Range> gaps_gamma52 = generator.getEachGapInfo();
		
		generator = ContigsStatsGenerator.getInstance().setInputScaffoldFile
		(contigs_gamma70).setSeqReadLength(seqLength).setConsiderGaps(true);
		if (!generator.generateStats()) return ;
		ArrayList<Range> gaps_gamma70 = generator.getEachGapInfo();
		
		
		finalRanges = new ArrayList<Range>();
		if (headers_7328 != null)
		FileUtilities.WriteToFile(diffs_7328,headers_7328 , 2);
		if (headers_gamma22 != null)
		FileUtilities.WriteToFile(diffs_gamma22,headers_gamma22 , 2);
		if (headers_gamma52 != null)
		FileUtilities.WriteToFile(diffs_gamma52,headers_gamma52 , 2);
		if (headers_gamma70 != null)
		FileUtilities.WriteToFile(diffs_gamma70,headers_gamma70 , 2);
		
		Random random = new Random();
		int totalRange = diffs_7328.size() + diffs_gamma22.size() + diffs_gamma52.size() + diffs_gamma70.size();
		
		
		for (Range range : diffs_7328)
		{
			if (contains(finalRanges,range,null) != 1)
			{
				String result = padded(random.nextInt(totalRange)) ;
				result = result + "\t1" ; 
				result = result + "\t" + contains(diffs_gamma22,range,gaps_gamma22);
				result = result + "\t" + contains(diffs_gamma52,range,gaps_gamma52) ;
				result = result + "\t" + contains(diffs_gamma70,range,gaps_gamma70) ;
				result = result + "\t" + contains(snpRangs_singleEnds,range,gaps_singleEnds);
				result = result + "\t" + range.getMetadata();
				Range r = new Range(range.getLowerLimit(), range.getUpperLimit(), result);
				finalRanges.add(r);
			}
		}
		
		for (Range range : diffs_gamma22)
		{
			if (contains(finalRanges,range,null) != 1)
			{
				String result = padded(random.nextInt(totalRange));
				result = result + "\t" + contains(diffs_7328,range,gaps_7328);
				result = result + "\t1" ; 
				result = result + "\t" + contains(diffs_gamma52,range,gaps_gamma52) ;
				result = result + "\t" + contains(diffs_gamma70,range,gaps_gamma70) ;
				result = result + "\t" + contains(snpRangs_singleEnds,range,gaps_singleEnds);
				result = result + "\t" + range.getMetadata();
				Range r = new Range(range.getLowerLimit(), range.getUpperLimit(), result);
				finalRanges.add(r);
			}
		}
		
		for (Range range : diffs_gamma52)
		{
			if (contains(finalRanges,range,null) != 1)
			{
				String result = padded(random.nextInt(totalRange));
				result = result + "\t" + contains(diffs_7328,range,gaps_7328);
				result = result + "\t" + contains(diffs_gamma22,range,gaps_gamma22) ;
				result = result + "\t1" ; 
				result = result + "\t" + contains(diffs_gamma70,range,gaps_gamma70) ;
				result = result + "\t" + contains(snpRangs_singleEnds,range,gaps_singleEnds);
				result = result + "\t" + range.getMetadata();
				Range r = new Range(range.getLowerLimit(), range.getUpperLimit(), result);
				finalRanges.add(r);
			}
		}
		
		for (Range range : diffs_gamma70)
		{
			if (contains(finalRanges,range,null) != 1)
			{
				String result = padded(random.nextInt(totalRange));
				result = result + "\t" + contains(diffs_7328,range,gaps_7328);
				result = result + "\t" + contains(diffs_gamma22,range,gaps_gamma22) ;
				result = result + "\t" + contains(diffs_gamma52,range,gaps_gamma52) ;
				result = result + "\t1" ; 
				result = result + "\t" + contains(snpRangs_singleEnds,range,gaps_singleEnds);
				result = result + "\t" + range.getMetadata();
				Range r = new Range(range.getLowerLimit(), range.getUpperLimit(), result);
				finalRanges.add(r);
			}
		}
		
		for (Range range : snpRangs_singleEnds)
		{
			if (contains(finalRanges,range,null) != 1)
			{
				String result = padded(random.nextInt(totalRange));
				result = result + "\t" + contains(diffs_7328,range,gaps_7328);
				result = result + "\t" + contains(diffs_gamma22,range,gaps_gamma22) ;
				result = result + "\t" + contains(diffs_gamma52,range,gaps_gamma52) ;
				result = result + "\t" + contains(diffs_gamma70,range,gaps_gamma70) ;
				result = result + "\t1" ; 
				Range r = new Range(range.getLowerLimit(), range.getUpperLimit(), result);
				finalRanges.add(r);
			}
		}
		
		
		//Range header = new Range(0, 0, "id\t7328\tGamma22\tGamma52\tGamma70\tReference\tStart\tEnd\tRef Nuc\tVar Nuc\tTotalDepth\tVar Freq");
//		finalRanges.add(header);
		Collections.sort(finalRanges,new RangeComparator());
		
		diffs_7328.clear();
		diffs_gamma22.clear();
		diffs_gamma52.clear();
		diffs_gamma70.clear();
		
//		PrepareAllFeaturesFiles allFeaturesFiles = new PrepareAllFeaturesFiles();
//		allFeaturesFiles.setGbkFile(args[9]);
//		allFeaturesFiles.run();
//		ArrayList<Range> genes = allFeaturesFiles.toRange(allFeaturesFiles.getGeneMap());
//		Collections.sort(genes,new RangeComparator());
//		
//		
//		TreeSet<String> genesMutated = new TreeSet<String>();
//		ArrayList<Range> allNews = new ArrayList<Range>(); 
//		for (Range range : finalRanges)
//		{
//			int lower = range.getLowerLimit();
//			int upper = range.getUpperLimit();
//			boolean flag = false;
//			for (Range annot : genes)
//			{
//				if ((annot.getUpperLimit() > lower && annot.getLowerLimit() < lower) ||
//						(annot.getUpperLimit() > upper && annot.getLowerLimit() < upper))
//				{
//					String gene = annot.getMetadata().split("\t")[0];
//					genesMutated.add(gene);
//					String newMetadata = range.getMetadata() + "\t" + gene;
//					range.setMetadata(newMetadata);
//					Range r = new Range(range.getLowerLimit(), range.getUpperLimit(), newMetadata);
//					allNews.add(r);
//					flag = true;
//				}
//			}
//			if (!flag)
//			{
//				allNews.add(range);
//			}
//		}
//		
//		
//		Set<String> cdsList = allFeaturesFiles.getCdsMap().keySet();
//		Set<String> rRnaList = allFeaturesFiles.getrRNA().keySet();
//		Set<String> tRnaList = allFeaturesFiles.getTrna().keySet();
//		Set<String> tmRnaList = allFeaturesFiles.getTmRNA().keySet();
//		Set<String> ncRnaList = allFeaturesFiles.getNcrna().keySet();
//		
//		PrintWriter pw = new PrintWriter(args[15]);  
//		for (String mutated : genesMutated)
//		{
//			String str = mutated;
//			if (cdsList.contains(mutated))
//			{
//				str = str + "\t" + "cds";
//			}
//			else if (rRnaList.contains(mutated))
//			{
//				str = str + "\t" + "rRNa";
//			}
//			else if (tRnaList.contains(mutated))
//			{
//				str = str + "\t" + "tRNA";
//			}
//			else if (tmRnaList.contains(mutated))
//			{
//				str = str + "\t" + "tmRNA";
//			}
//			else if (ncRnaList.contains(mutated))
//			{
//				str = str + "\t" + "ncRNA";
//			}
//			pw.println(str);
//		}
//		pw.flush();
//		pw.close();
		
//		Range header = new Range(0, 0, "id\t7328\tGamma22\tGamma52\tGamma70\tReference\tStart\tEnd\tRef Nuc\tVar Nuc\tTotalDepth\tVar Freq");
//		finalRanges.add(header);
		if (headers != null)
		FileUtilities.WriteToFile(finalRanges,headers , 2);
//		FileUtilities.WriteToFile(allNews,args[14] , 2);
	}
	
	private static boolean checkInGaps(ArrayList<Range> gaps, Range range)
	{
		for (Range annot : gaps)
		{
			if (!(range.getUpperLimit() < annot.getLowerLimit() || range.getLowerLimit() > annot.getUpperLimit()))
			{
				return true;
			}
		}
		return false;
	}

	private static String padded(int nextInt) {
		String result = String.valueOf(nextInt);
		int diff = 5 - result.length();
		for (int i = 0; i < diff ; i++) result = "0" + result;
		result = "Diff_" + result;
		return result;
	}

	private static int contains(ArrayList<Range> finalRanges, Range range, ArrayList<Range> gaps) {
		int result = 0;
		for(Range r : finalRanges)
		{
			if (r.getUpperLimit() == range.getUpperLimit() &&
					r.getLowerLimit() == range.getLowerLimit())
			{
				result = 1;
				break;
			}
		}
		if (gaps != null)
		{
			boolean inGaps = checkInGaps(gaps, range);
			if (result==1 && inGaps)
			{
				System.out.println("Cannot be in gaps as well as have differences");
				System.exit(-1);
			}
			else if (result == 0)
			{
				if (inGaps) return 2;
				else return 0;
			}
		}
		return result;
	}

	public static ArrayList<Range> fetchDifferences(String[] filters, String fileName) throws Exception {
		Set<String> set = OtherUtilities.fastaHeader(fileName,filters);
		ArrayList<Range> diffs = new ArrayList<Range>();
		for(String d : set)
		{
			String[] params = d.split("\t");
			Range range = new Range(Integer.parseInt(params[1]), Integer.parseInt(params[2]), d);
			diffs.add(range);
		}
		return diffs;
	}

	public PrepareSNPTable setAllDiffsFile_7328(String allDiffsFile_7328) {
		this.allDiffsFile_7328 = allDiffsFile_7328;
		return this;
	}

	public PrepareSNPTable setHeaders_7328(String headers_7328) {
		this.headers_7328 = headers_7328;
		return this;
	}

	public PrepareSNPTable setAllDiffsFile_gamma22(String allDiffsFile_gamma22) {
		this.allDiffsFile_gamma22 = allDiffsFile_gamma22;
		return this;
	}

	public PrepareSNPTable setHeaders_gamma22(String headers_gamma22) {
		this.headers_gamma22 = headers_gamma22;
		return this;
	}

	public PrepareSNPTable setAllDiffsFile_gamma52(String allDiffsFile_gamma52) {
		this.allDiffsFile_gamma52 = allDiffsFile_gamma52;
		return this;
	}

	public PrepareSNPTable setHeaders_gamma52(String headers_gamma52) {
		this.headers_gamma52 = headers_gamma52;
		return this;
	}

	public PrepareSNPTable setAllDiffsFile_gamma70(String allDiffsFile_gamma70) {
		this.allDiffsFile_gamma70 = allDiffsFile_gamma70;
		return this;
	}

	public PrepareSNPTable setHeaders_gamma70(String headers_gamma70) {
		this.headers_gamma70 = headers_gamma70;
		return this;
	}

	public PrepareSNPTable setHeaders(String headers) {
		this.headers = headers;
		return this;
	}

	public PrepareSNPTable setGbkFile(String gbkFile) {
		this.gbkFile = gbkFile;
		return this;
	}

	public PrepareSNPTable setContigs_7328(String contigs_7328) {
		this.contigs_7328 = contigs_7328;
		return this;
	}

	public PrepareSNPTable setContigs_gamma22(String contigs_gamma22) {
		this.contigs_gamma22 = contigs_gamma22;
		return this;
	}

	public PrepareSNPTable setContigs_gamma52(String contigs_gamma52) {
		this.contigs_gamma52 = contigs_gamma52;
		return this;
	}

	public PrepareSNPTable setContigs_gamma70(String contigs_gamma70) {
		this.contigs_gamma70 = contigs_gamma70;
		return this;
	}

	public PrepareSNPTable setWithGenes(String withGenes) {
		this.withGenes = withGenes;
		return this;
	}

	public PrepareSNPTable setTilingFile(String tilingFile) {
		this.tilingFile = tilingFile;
		return this;
	}

	public PrepareSNPTable setSnps(String snps) {
		this.snps = snps;
		return this;
	}
	
	public PrepareSNPTable setSeqLength(int seqLength) {
		this.seqLength = seqLength;
		return this;
	}
	
	public ArrayList<Range> getFinalRanges()
	{
		return new ArrayList<Range>(finalRanges);
	}
	
	public ArrayList<ArrayList<Range>> getRanges()
	{
		ArrayList<ArrayList<Range>> result = new ArrayList<ArrayList<Range>>(5);
		for (int i = 0 ; i < 5; i++)
		{
			result.add(new ArrayList<Range>());
		}
		for (Range range : finalRanges)
		{
			String meta = range.getMetadata();
			String[] params = meta.split("\t");
			for (int i = 1; i <=5; i++)
			{
				if (params[i].trim().equals("1"))
				{
//					ArrayList<Range> lst = null;
//					if(result.size() < i)
//						lst = new ArrayList<Range>();
//					else
					ArrayList<Range> lst = result.get(i - 1);
					lst.add(range);
					result.set(i-1, lst);
				}
			}
		}
		return result;
	}
}
